package fr.Orm.pierop.com;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.PropertyUtils;

import fr.dbManager.pierop.com.DBManager;
import fr.myExceptions.pierop.com.DBManagerSingletonException;
import fr.myExceptions.pierop.com.databaseMultipleDefinitionIdException;
import fr.myExceptions.pierop.com.nullaryContructorException;

class facadeJDBC implements IFacadeJDBC {

	private static		facadeJDBC	singletonObject = null;
	
	private DBManager	db;
	
	private Map<String, Map<String, String>>	tableMap;
	private	Map<String, String>					classMap;
	
	private			facadeJDBC(	Map<String, Map<String, String>> tableMap, 
								Map<String, String> classMap) 
								throws DBManagerSingletonException
	{
		this.db = DBManager.getInstance();
		this.tableMap = tableMap;
		this.classMap = classMap;
	}
	
	public static	facadeJDBC getInstance(	Map<String, Map<String, String>> tableMap, 
											Map<String, String> classMap) 
											throws DBManagerSingletonException
	{
		if (facadeJDBC.singletonObject == null)
			facadeJDBC.singletonObject = new facadeJDBC(tableMap, classMap);
		return facadeJDBC.singletonObject;
	}
	
	@Override
	public void create(Object obj) throws Exception {
		
		boolean	cnd	= false;
		String	c = utilsFacade.isPersist(obj, this.classMap);
		Map<String, String> m = this.tableMap.get(c);
		String 	query = "INSERT INTO " + c + "(", queryCol = "", queryVal = "";
		
		for (Field f : Class.forName(obj.getClass().getName()).getDeclaredFields())
		{
			utilsFacade.isNullId(obj, f, m);
			if (PropertyUtils.getSimpleProperty(obj, f.getName()) != null)
			{
				if (cnd) { queryCol = queryCol + ", "; queryVal = queryVal + ", "; } else cnd = true;
				queryVal = queryVal + utilsFacade.isString(obj, f);
				queryCol = queryCol + m.get(f.getName());
			}
		}
		if (cnd == true) {
			query = query + queryCol + ") VALUES(" + queryVal + ")";
			try { this.db.update(query); }
			catch (Exception e) { 
				throw new databaseMultipleDefinitionIdException("Multiple definition d'Id pour la classe " + c);
			}
		}
	}

	@Override
	public void update(Object obj) throws Exception {
		
		boolean	cnd	= false;
		String c = utilsFacade.isPersist(obj, this.classMap);
		Map<String, String> m = this.tableMap.get(c);
		String	query = "UPDATE " + c + " SET ", queryWhere = "";
		
		for (Field f : Class.forName(obj.getClass().getName()).getDeclaredFields())
		{
			utilsFacade.isNullId(obj, f, m);
			if (PropertyUtils.getSimpleProperty(obj, f.getName()) != null)
				if (m.get(f.getName()).equals("ID"))
					queryWhere += " WHERE ID=" + PropertyUtils.getSimpleProperty(obj, f.getName());
				else
				{
					if (cnd) { query += ", "; } else cnd = true;
					query = query + m.get(f.getName()) + "=";
					query = query + utilsFacade.isString(obj, f);
				}
		}
		this.db.update(query + queryWhere);
	}

	@Override
	public void delete(Object obj) throws Exception {
		String	c = utilsFacade.isPersist(obj, this.classMap);
		Map<String, String> m = this.tableMap.get(c);
		String query = "DELETE FROM " + c + " WHERE ID=";
		for (Field f : Class.forName(obj.getClass().getName()).getDeclaredFields())
		{
			utilsFacade.isNullId(obj, f, m);
			if (m.get(f.getName()).equals("ID")) query += PropertyUtils.getSimpleProperty(obj, f.getName());
		}
		this.db.update(query);
	}

	@Override
	public Object select(Class c, Integer id) throws Exception {
		
		String	classe = this.classMap.get(c.getCanonicalName());
		Map<String, String> m = this.tableMap.get(classe);
		try {
			Object obj = Class.forName(c.getCanonicalName()).newInstance();
			String query = "SELECT * FROM " + classe + " WHERE ID = " + id;
			ResultSet r = this.db.execute(query);
			if (r.next())
			{
				Iterator<Entry<String, String>> it = m.entrySet().iterator();
				while (it.hasNext())
				{
					Map.Entry<String, String> e = it.next();
					PropertyUtils.setSimpleProperty(obj, e.getKey(), r.getObject(e.getValue()));
				}
			}
			return obj;
		}
		catch ( java.lang.InstantiationException e ) { throw new nullaryContructorException(); }
	}

}